#include "menu.hpp"

MenuScreen Menu;

class MenuItem
{
public:
	virtual const wchar_t* WString() = 0;
	
	virtual void Init()
	{
	}

	virtual void Act()
	{
	}

	virtual void Adjust(int dval)
	{
	}
};

#include "app.hpp"
#include "select.hpp"

#include "music.hpp"
#include "sound.hpp"
enum
{
	CURSOR,
	BUZZ,
	SNDCT
};
static Sound *snds[SNDCT];

#include "audio.hpp"

class PlayItem : public MenuItem
{
public:
	const wchar_t* WString() 
	{
		return L"PLAY GAME";
	}

	void Act()
	{
		Game.StatReset();
		App.ScreenChange(&Select);
		//Mus.Stop();
		Aud.SoundPlay(*snds[CURSOR]);
	}
}
	playitem;

class OptsItem : public MenuItem
{
public:
	const wchar_t* WString() 
	{
		return L"OPTIONS";
	}

	void Act();
}
	optsitem;

#include "input.hpp"

class KBindItem : public MenuItem
{
public:
	KBindItem(int n)
	{
		cmd = n;
	}

	const wchar_t* WString()
	{
		return wstr.c_str();
	}

	void Init()
	{
		wstr = Inp.CmdWStr(cmd);
		for (const char *kschar = Inp.CmdKeyStr(cmd); *kschar; ++kschar)
		{
			wstr.push_back((wchar_t)*kschar);
		}
	}

	void Act()
	{
		Menu.BindStart(this, Inp.KEYBINDING, cmd);
	}

private:
	int cmd;

	std::wstring wstr;
};

static KBindItem
	lkitem(Inp.LEFT),
	rkitem(Inp.RIGHT),
	ukitem(Inp.UP),
	dkitem(Inp.DOWN),
	skitem(Inp.SHOOT),
	agkitem(Inp.AIMGUN);

class KeysItem : public MenuItem
{
public:
	const wchar_t* WString()
	{
		return L"KEY CONFIG";
	}

	void Act()
	{
		MenuItem *items[] =
		{
			&lkitem,
			&rkitem,
			&ukitem,
			&dkitem,
			&skitem,
			&agkitem,
			&optsitem,
			0
		};

		Menu.Clear();
		Menu.Push(items);
		Aud.SoundPlay(*snds[CURSOR]);
	};
}
	keysitem;

#include <sstream>

class AudioItem : public MenuItem
{
public:
	enum
	{
		SOUND,
		MUSIC
	};

	AudioItem(int a)
		: which(a), chan(-1)
	{
	}

	const wchar_t* WString()
	{
		return wstr.c_str();
	}

	void Init()
	{
		static const wchar_t *WSTRS[] = 
		{
			L"SOUND   ",
			L"MUSIC   "
		};

		vol = (which == SOUND) ? Aud.Vol() : Mus.On();
		std::wstringstream volstr;
		volstr << vol;
		wstr = WSTRS[which];
		wstr += volstr.str();
	}

	void Adjust(int d)
	{
		if (which == SOUND)
		{
			Aud.Vol(vol + d);
			chan = Aud.SoundPlay(*snds[CURSOR], chan);
		}
		else
		{
			//if (Mus.On())
			//{
			//	Mus.Close();
			//}
			//else
			//{
			//	Mus.Open();
			//	Mus.Play(Mus.MENU);
			//}
			//vol = (int)Mus.On();
		}

		Init();
	}

private:
	int which;
	int chan;
	int vol;
	std::wstring wstr;
};

static AudioItem snditem(AudioItem::SOUND),
		 musitem(AudioItem::MUSIC);

class ExitItem : public MenuItem
{
public:
	const wchar_t* WString() 
	{
		return L"EXIT GAME";
	}

	void Act()
	{
		App.Exit();
	}
}
	exititem;

class MainItem : public MenuItem
{
public:
	const wchar_t* WString() 
	{
		return L"MAIN MENU";
	}

	void Act()
	{
		MenuItem *items[] =
		{
			&playitem, 
			&optsitem,
			&exititem,
			0
		};

		Menu.Clear();
		Menu.Push(items);
	}
}
	mainitem;

// not in-class because requires other items defined
void OptsItem::Act()
{
	MenuItem *items[] =
	{
		&keysitem,
		//&joyitem,
		&snditem,
		&musitem,
		&mainitem,
		0
	};

	Menu.Clear();
	Menu.Push(items);
	Aud.SoundPlay(*snds[CURSOR]);
}

void MenuScreen::Clear()
{
	items.clear();
	cursor = 0;
}

void MenuScreen::Push(MenuItem *newitems[])
{
	for (int e = 0; newitems[e]; ++e)
	{
		items.push_back(newitems[e]);
		items.back()->Init();
	}
}

void MenuScreen::BindStart(MenuItem *item, int bindtype, int bindcmd)
{
	Inp.BindStart(bindtype, bindcmd);
	switch (bindtype)
	{
	case Input::KEYBINDING:
		bindmenu = &keysitem;
		break;
	
	default:
		;
	}
	binditem = item;
}

#include "image.hpp"

static Image *fontimg;

bool MenuScreen::Open()
{
	cursor = 0;
	bindmenu = NULL;
	binditem = NULL;

	fontimg = AllImgs.Get("font");

	const char *SNDSTRINGS[] =
	{
		"cursor",
		"buzz",
	};

	AllSnds.BatchGet(snds, SNDCT, "menu/", SNDSTRINGS);
	if (!Mus.Opened())
	{
		Mus.Open("menu");
		Mus.Play(-1);
	}

	mainitem.Act();
	Inp.KeyRepeat(true);

	return fontimg != 0;
}

void MenuScreen::Close()
{
	Inp.Save();
	Inp.KeyRepeat(false);
	AllImgs.Clear();
}

#include "input.hpp"

void MenuScreen::In()
{
	if (binditem && bindmenu)
	{
		int bindcurs = cursor;

		switch (Inp.BindState())
		{
		case Input::BINDOK:
			bindmenu->Act();
			cursor = bindcurs;
			Inp.Save();
			break;

		case Input::BINDFAIL:
			Aud.SoundPlay(*snds[BUZZ]);
			break;

		default:
			return;
		}

		bindmenu = NULL;
		binditem = NULL;
		return;
	}

	int dcursor = Inp.CmdEdge(Inp.DOWN) - Inp.CmdEdge(Inp.UP);
	if (dcursor)
	{
		cursor += dcursor;
		int itemct = items.size();
		cursor = (cursor % itemct + itemct) % itemct;
		//Aud.SoundPlay(*snds[CURSOR]);
	}

	int dval = Inp.CmdEdge(Inp.RIGHT) - Inp.CmdEdge(Inp.LEFT);
	if (dval)
	{
		items[cursor]->Adjust(dval);
	}

	if (Inp.CmdEdge(Inp.ENTER) || Inp.CmdEdge(Inp.SHOOT))
	{
		items[cursor]->Act();
	}

	if (Inp.CmdEdge(Inp.EXIT) || Inp.CmdEdge(Inp.AIMGUN))
	{
		items.back()->Act();
	}
}

void MenuScreen::Update()
{
}

#include "camera.hpp"
#include "video.hpp"
#include "audio.hpp"

void MenuScreen::Out(float upfrac)
{
	Cam.Pos(0, 0);
	Cam.Out(upfrac);

	for (int i = 0; i < (int)items.size(); ++i)
	{
		float blue = (i == cursor ? 1 : .5f);
		float red = (items[i] == binditem ? 1 : .5f);
		Vid.Color(red, .5f, blue, 1);
		Vid.Pos(20, 4 + (2 * i));
		
		const wchar_t *wstr = items[i]->WString();
		Vid.TilesDraw(*fontimg, wstr, std::wcslen(wstr), 1);
	}

	Vid.Color(1, 1, 1, 1);
}
